<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Helpers\Auth;
use App\Helpers\URL;
use App\Services\AuthService;
use InvalidArgumentException;
use Riverside\Express\Application;
use Riverside\Express\Request;
use Riverside\Express\Response;

class AuthController
{
    /**
     * Obtiene los campos necesarios para registrar un usuario.
     */
    private function getSignupFields(): array
    {
        return ['username', 'email', 'password', 'confirm_password'];
    }

    /**
     * Obtiene una instancia del servicio de autenticación.
     */
    private function authService(Application $app): AuthService
    {
        return new AuthService($app);
    }

    /**
     * Obtiene los campos necesarios para crear una sesión.
     */
    private function getLoginFields(): array
    {
        return ['nickname', 'password'];
    }

    /**
     * Muestra la vista de registro de usuarios.
     */
    public function signupView(Request $req, Response $res): void
    {
        $validations = $values = $status = [];
        $error = $req->session['error'] ?? null;
        $event = $req->query[URL::getQueryEventName()] ?? null;

        // Obtiene los errores de validación y los valores de los campos.
        foreach ($this->getSignupFields() as $field) {
            $validations[$field] = $req->session['validations'][$field] ?? null;
            $values[$field] = $req->session['values'][$field] ?? null;
            $status[$field] = isset($validations[$field]) ? 'error' : null;
        }

        foreach (['validations', 'values', 'error'] as $key) {
            unset($req->session[$key]);
        }

        $res->render('auth/signup', [
            'app' => $req->app,
            'validations' => $validations,
            'values' => $values,
            'status' => $status,
            'error' => $error,
            'event' => $event,
        ]);
    }

    /**
     * Registra un nuevo usuario.
     */
    public function signupAction(Request $req, Response $res): void
    {
        $data = [];

        // Obtiene solo los campos necesarios de la petición.
        foreach ($this->getSignupFields() as $field) {
            $data[$field] = $req->body[$field] ?? null;
        }

        try {
            // Registra la información del usuario.
            $this->authService($req->app)->register($data);
        } catch (InvalidArgumentException $e) {
            $gump = $req->app->local('gump');

            $req->session['validations'] = $gump->get_errors_array();
            $req->session['values'] = $data;
            $req->session['error'] = $e->getMessage();

            $res->redirect(URL::event('signup', 'signupAction'));
        }

        $req->session['success'] = 'Tu cuenta se ha registrado correctamente';

        $res->render('components/redirect', ['url' => URL::site('login')]);
    }

    /**
     * Muestra la vista de inicio de sesión.
     */
    public function loginView(Request $req, Response $res): void
    {
        $validations = $values = $status = [];
        $success = $req->session['success'] ?? null;
        $error = $req->session['error'] ?? null;
        $event = $req->query[URL::getQueryEventName()] ?? null;

        // Obtiene los errores de validación y los valores de los campos.
        foreach ($this->getLoginFields() as $field) {
            $validations[$field] = $req->session['validations'][$field] ?? null;
            $values[$field] = $req->session['values'][$field] ?? null;
            $status[$field] = isset($validations[$field]) ? 'error' : null;
        }

        foreach (['validations', 'values', 'success', 'error'] as $key) {
            unset($req->session[$key]);
        }

        $res->render('auth/login', [
            'app' => $req->app,
            'validations' => $validations,
            'values' => $values,
            'status' => $status,
            'success' => $success,
            'error' => $error,
            'event' => $event,
        ]);
    }

    /**
     * Crea la sesión de un usuario.
     */
    public function loginAction(Request $req, Response $res): void
    {
        $data = [];

        // Obtiene solo los campos necesarios de la petición.
        foreach ($this->getLoginFields() as $field) {
            $data[$field] = $req->body[$field] ?? null;
        }

        try {
            // Obtiene la sesión del usuario.
            $session = $this->authService($req->app)->getSession($data);
        } catch (InvalidArgumentException $e) {
            $gump = $req->app->local('gump');

            $req->session['validations'] = $gump->get_errors_array();
            $req->session['values'] = $data;
            $req->session['error'] = $e->getMessage();

            $res->redirect(URL::event('login', 'loginAction'));
        }

        $options = Auth::getCookieOptions();
        $options[Auth::getExpirationVarname()] = Auth::generateCookieExpiration();

        // Genera la cookie de autenticación.
        $res->cookie(Auth::getCookieVarname(), $session, $options);

        $res->render('components/redirect', ['url' => URL::site('contacts')]);
    }

    /**
     * Cierra la sesión de un usuario autenticado.
     */
    public function logout(Request $req, Response $res): void
    {
        $res->clearCookie(Auth::getCookieVarname(), Auth::getCookieOptions());

        $res->redirect(URL::site('login'));
    }
}
